package org.caster.client;

import com.jme3.app.SimpleApplication;
import com.jme3.asset.plugins.FileLocator;
import com.jme3.material.Material;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.scene.Spatial;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.controls.DropDown;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Created by IntelliJ IDEA.
 * User: demoth
 * Date: 8/13/12
 * Time: 3:23 PM
 * <p/>
 * Draws the model and stores commands from user in 'out'
 */
public class GameEngine extends SimpleApplication {
    private Queue<JSONObject> out;
    private Queue<JSONObject> in;
    private WorldModel model;
    private org.slf4j.Logger logger;

    Nifty nifty;
    private ScreenController controller;

    public GameEngine(Queue<JSONObject> in, Queue<JSONObject> out, WorldModel model) {
        this.in = in;
        this.out = out;
        this.model = model;
        this.controller = new CasterScreenController(out, model);
        this.logger = LoggerFactory.getLogger(GameEngine.class);

        // go fuck yourself you asshole
        Logger.getLogger("").setLevel(Level.SEVERE);
    }

    @Override
    public void simpleInitApp() {
        NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);
        this.nifty = niftyDisplay.getNifty();
        assetManager.registerLocator("/media/f9157386-4243-4142-836c-e97e978bb8ba/media/devel/src/java/client/jCaster/res", FileLocator.class);

        nifty.fromXml("gui/gui.xml", "login", controller);
        guiViewPort.addProcessor(niftyDisplay);
        inputManager.setCursorVisible(true);
        flyCam.setEnabled(false);

        loadModels();
    }

    private void loadModels() {
        model.tileTypes = new LinkedHashMap<>();
        model.tileTypes.put("floor", assetManager.loadModel("terrain/floor.obj"));
        model.tileTypes.put("wall", assetManager.loadModel("terrain/wall.obj"));
        model.materials = new LinkedHashMap<>();
        Material floor = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        floor.setTexture("ColorMap", assetManager.loadTexture("terrain/floor.jpg"));
        model.materials.put("floor", floor);

        Material wall = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        wall.setTexture("ColorMap", assetManager.loadTexture("terrain/wall.jpg"));
        model.materials.put("wall", wall);
    }

    @Override
    public void update() {
        super.update();
        if (!in.isEmpty()) {
            try {
                JSONObject json = in.poll();
                logger.info("got " + json);

                switch (json.getString("what")) {
                    case "environment":
                        // too bad i cannot modify geometry from here. exception is thrown
                        model.environmentUpdates.add(json);
                        //updateEnvironment(json);
                        break;
                    case "logon":
                        model.isLoggedIn = true;
                        break;
                    case "login":
                        addCreatures(json.get("creatures"));
                        break;
                    case "fail":
                        break;
                    case "response":
                        break;
                    case "exit":
                        break;

                }
            } catch (JSONException пошёлнахуй) {

            }
        }

        if (!model.environmentUpdates.isEmpty()) {
            try {
                updateEnvironment(model.environmentUpdates.poll());
            } catch (JSONException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }

        }

        if (!model.nextScreen.isEmpty()) {
            nifty.gotoScreen(model.nextScreen);
            if (model.nextScreen.equals("creature_select"))
                populate(model.creatures);

            else if (model.nextScreen.equals("game")) {
                flyCam.setEnabled(true);
                rootNode.attachChild(model.terrainNode);
            }

            model.nextScreen = "";
        }


    }

    private void addCreatures(Object creatures) throws JSONException {
        if (creatures instanceof JSONArray) {
            model.creatures = new ArrayList<>();
            for (int i = 0; i < ((JSONArray) creatures).length(); i++) {
                model.creatures.add(((JSONArray) creatures).getString(i));
            }
            model.nextScreen = "creature_select";
        }
    }

    private void populate(List<String> creatures) {
        Screen screen = nifty.getScreen("creature_select");
        DropDown niftyControl = screen.findNiftyControl("dropDown", DropDown.class);
        niftyControl.addAllItems(creatures);
    }

    @Override
    public void destroy() {
        super.destroy();
        ClientMain.DONE = true;
    }

    private void updateEnvironment(JSONObject environment) throws JSONException {
        Iterator keys = environment.keys();
        while (keys.hasNext()) {
            String key = keys.next().toString();
            if (key.equals("what"))
                continue;
            int x = Integer.parseInt(key.split(",")[0]);
            int y = Integer.parseInt(key.split(",")[1]);
            String terrain = environment.getJSONObject(key).get("terrain").toString();
            Spatial tile = model.tileTypes.get(terrain).clone();
            tile.setMaterial(model.materials.get(terrain));
            tile.setName(key);
            tile.move(2 * x, 0, 2 * y);
            model.terrainNode.attachChild(tile);
            model.nextScreen = "game";

        }
    }
}
